// import Vue from 'vue'
import { NodeType, StageType } from '@/model/node.model'
import { Graph } from '@antv/x6'
import RuleChainEdge from '../edge/edge'
import registerRouter from './router'
import '../node/node.register'
import { Message } from 'element-ui'
import { debounce } from '@/utils/helper/jsUtil'

class MainCanvas {
  constructor(target) {
    this.graph = null
    this.edge = null

    this.init(target)
  }

  init(target) {
    this._initGraph(target)
    this._initEdge()
  }

  _initGraph(target) {
    registerRouter()
    this.graph = new Graph({
      container: target,
      autoResize: true,
      // 注意：x6 graph中不能设置async属性，会影响stage的创建和节点层级结构
      // async: true,
      background: '#f2f3f5',
      panning: true,
      history: {
        enabled: true,
        beforeAddCommand(event, args) {
          if (args.key === 'tools' || args.key === 'attrs') {
            return false
          }
          if (args.cell.isNode() && args.cell.children) {
            return false
          }
          return true
        }
      },
      grid: {
        size: 15,
        visible: true,
        type: 'mesh',
        args: {
          color: '#f7f8fa',
          thickness: 2
        }
      },
      // 连线设置
      connecting: {
        snap: true,
        allowBlank: false,
        allowLoop: false,
        allowNode: false,
        allowMulti: 'withPort',
        allowEdge: false,
        validateConnection({ targetView, sourceMagnet, sourcePort, targetMagnet, targetPort, sourceCell, targetCell }) {
          const sourceType = sourceMagnet ? sourceMagnet.getAttribute('port-group') : sourceCell.getPort(sourcePort - 0).group // 浏览器兼容
          // 如果目标不存在则不创建
          if (!targetPort) {
            return false
          }

          // 连线只能从out连接到in
          if (sourceType === 'in' || targetMagnet.getAttribute('port-group') !== 'in') {
            return false
          }

          // 来源节点和目标节点仅能存在一条连线，不能重复链接
          const outEdges = this.getOutgoingEdges(sourceCell).filter(edge => edge.getTargetPortId() === Number(targetPort))
          if (outEdges.length) {
            return false
          }

          // 目标节点不能是源节点的祖先节点
          if (targetView && this.isPredecessor(sourceCell, targetCell)) {
            return false
          }

          // 开始节点只能有一条输出分支
          if (sourceCell.data.type === NodeType.startNode && this.getConnectedEdges(sourceCell).length > 1) {
            return false
          }

          // 并行开始节点限制连出去的线的数量
          if (sourceCell.data.additionalInfo?.component === 'AdvancedLibParallelStartNode') {
            const port = sourceCell.getPorts().find(item => item.group === 'out')
            const edgeSourceList = this.getEdges().filter(item => item.getSource().port - 0 === port.id - 0)
            if (edgeSourceList.length > 6) {
              showMsg()
              return false
            }
          }

          const sourceParent = sourceCell.getParent()
          const targetParent = targetCell.getParent()

          // 并行结束节点的输出不能连接到当前并行区域内的节点
          if (sourceType === 'out' && sourceCell.data.additionalInfo.component === 'AdvancedLibParallelEndNode' && targetParent?.id === sourceParent.id) {
            return false
          }

          // 不可跨父节点链接
          if ((sourceParent && !targetParent) || (!sourceParent && targetParent) || (sourceParent && targetParent && sourceParent.id !== targetParent.id)) {
            // 如果来源节点或目标节点是并行区域内的节点，以下情况可以连接
            if ((sourceParent && sourceParent.data.additionalInfo?.component === 'AdvancedLibParallelNode') || (targetParent && targetParent.data.additionalInfo?.component === 'AdvancedLibParallelNode')) {
              // 如果是并行节点且处于阶段模式下，area有值
              const sourceArea = sourceParent ? sourceParent.getParent() : null
              const targetArea = targetParent ? targetParent.getParent() : null
              const stageMode = Object.values(StageType).includes(sourceArea?.id) || Object.values(StageType).includes(targetArea?.id)

              // 如果即处于简单模式下，仅能连接以下三种情况
              // a. 并行结束连接并行开始
              // b. 并行结束连接其他节点
              // c. 其他节点连接并行开始
              if (!stageMode) {
                if (
                  (sourceParent && targetParent && sourceCell.data.additionalInfo?.component === 'AdvancedLibParallelEndNode' && targetCell.data.additionalInfo?.component === 'AdvancedLibParallelStartNode') ||
                  (sourceParent && !targetParent && sourceCell.data.additionalInfo?.component === 'AdvancedLibParallelEndNode') ||
                  (!sourceParent && targetParent && targetCell.data.additionalInfo?.component === 'AdvancedLibParallelStartNode')
                ) {
                  return true
                }
              } else {
                // 如果处于阶段模式下，需进行以下判断
                // a. 来源节点是阶段内节点，目标节点是并行节点，则目标节点需是并行开始节点，且来源和目标处于相同阶段
                // b. 来源节点是并行节点，目标节点是阶段内节点，则来源节点需是并行结束节点，且来源和目标处于相同阶段
                // c. 来源和目标都是并行节点，则来源节点需是并行结束节点，目标节点需是并行开始节点
                if (
                  (!targetArea && sourceArea && sourceArea.id === targetParent.id && sourceCell.data.additionalInfo?.component === 'AdvancedLibParallelEndNode') ||
                  (!sourceArea && targetArea && targetArea.id === sourceParent.id && targetCell.data.additionalInfo?.component === 'AdvancedLibParallelStartNode')
                ) {
                  return true
                }
                if (targetArea && sourceArea && targetArea.id === sourceArea.id && sourceCell.data.additionalInfo?.component === 'AdvancedLibParallelEndNode' && targetCell.data.additionalInfo?.component === 'AdvancedLibParallelStartNode') {
                  return true
                }
              }
            }
            return false
          }

          return true
        }
      },
      // 节点选择
      selecting: {
        enabled: true,
        multiple: false
      },
      // 放大缩小
      mousewheel: {
        enabled: true,
        modifiers: ['ctrl', 'meta'],
        factor: 1.1,
        minScale: 0.5,
        maxScale: 3
      },
      // 自定义节点连接桩
      onPortRendered(args) {
        const selectors = args.contentSelectors
        const container = selectors && selectors.foContent
        if (container) {
          const port = document.createElement('div')
          port.className = 'node-port'
          container.appendChild(port)
        }
      },
      onEdgeLabelRendered(args) {
        // 注意，连线的删除按钮分为两个部分定义
        // 此处定义有标签时的删除按钮
        // 无标签的删除按钮在rulechain-page.vue中定义
        const { edge, label, selectors } = args
        const container = selectors && selectors.foContent
        const _self = this
        const labelRemoveBtn = document.createElement('div')
        labelRemoveBtn.className = 'edge-remove el-icon-close'
        labelRemoveBtn.addEventListener('click', () => {
          _self.removeEdge(edge)
        })
        if (label && container) {
          const nodeLabel = document.createElement('div')
          nodeLabel.className = 'node-label'
          let text = label.attrs.label.text // 超出省略
          if (text.length > 4) { text = text.slice(0, 4) + '..' }
          nodeLabel.innerText = text
          nodeLabel.appendChild(labelRemoveBtn)
          container.className = 'node-label-container'
          container.appendChild(nodeLabel)
        }
      },
      // 节点和边的交互
      interacting: {
        // 节点是否可拖动
        nodeMovable(args) {
          const { cell } = args
          if (cell.isNode()) {
            return !cell.getData().disableMove
          }
          return true
        }
      },
      // 允许节点可以添加到父组中
      embedding: {
        enabled: true,
        findParent({ node }) {
          const bbox = node.getBBox()
          const additionalInfo = node.data?.additionalInfo || {}
          const res = this.getNodes().filter((nodeItem) => {
            // 往并行区域放节点，有些限制
            if (nodeItem.data?.additionalInfo?.component === 'AdvancedLibParallelNode') {
              if (!additionalInfo.newNode) { // 非新增的节点
                if ((!additionalInfo.parallelOrder) || additionalInfo.parallelOrder !== nodeItem.data.additionalInfo.parallelOrder) { // 非当前并行组的节点不能进组
                  return false
                }
              } else { // 左侧拖进来的新增的节点
                if (additionalInfo.component === 'AdvancedLibParallelStartNode') { // 往并行节点里拖进去个并行节点肯定不行
                  return false
                }
              }
            }
            // 往阶段模式里放节点，有些限制
            if (['start-stage-node', 'end-stage-node'].includes(nodeItem.id)) {
              if (!additionalInfo.newNode) { // 非新增的节点
                if (node.getParent()?.id !== nodeItem.id) { // 已在阶段里的节点，不允许更换其阶段
                  return false
                }
              }
            }
            if (nodeItem.children && nodeItem.id !== node.id) {
              const targetBBox = nodeItem.getBBox()
              return bbox.isIntersectWithRect(targetBBox)
            }
            return false
          })
          // 渲染顺序错误时（先子后父），将阶段节点改为祖父节点，并行节点改为父节点
          if (res.length > 1 && res[0].data.additionalInfo) {
            const parallel = res.shift()
            res.push(parallel)
          }
          return res
        }
      },
      // 限制节点移动范围
      translating: {
        restrict(view) {
          const cell = view.cell
          if (cell.isNode()) {
            const parent = cell.getParent()
            if (parent) {
              const range = 1000 // 设置节点可外移多远
              const wrapper = { ...window.stageWrapper } // 获取阶段组件信息，浅拷贝
              wrapper.x = wrapper.x + 30 // 边框预留padding30
              wrapper.width = wrapper.width + range
              if (parent?.id === 'start-stage-node') { // 开始阶段
                wrapper.y = wrapper.y - range
                wrapper.height = wrapper.height + 2 * range - 30
                // wrapper.height = wrapper.height - range // 删除此行和下边同样的注释那行可开启开始阶段向下扩展功能 该功能测试中
                return wrapper
              } else if (parent?.id === 'end-stage-node') { // 结束阶段
                wrapper.y = wrapper.y + wrapper.height + 30
                wrapper.height = wrapper.height + range
                return wrapper
              } else if (parent.getParent() && parent.data?.additionalInfo.component === 'AdvancedLibParallelNode') { // 阶段模式下并行子节点不能超出阶段模式范围
                const stageNode = parent.getParent()
                wrapper.x = wrapper.x + 30
                wrapper.width = wrapper.width - 60
                if (stageNode.id === 'start-stage-node') {
                  wrapper.y = wrapper.y - range + 30
                  wrapper.height = wrapper.height + 2 * range - 90
                  // wrapper.height = wrapper.height - range // 删除此行和上边同样的注释那行可开启开始阶段向下扩展功能 该功能测试中
                } else if (stageNode.id === 'end-stage-node') {
                  wrapper.y = wrapper.y + wrapper.height + 60
                  wrapper.height = wrapper.height + range - 30
                }
                return wrapper
              }
            }
          }
          return null
        }
      }
    })

    // 监听窗口变化，重绘画布大小
    window.addEventListener('resize', debounce(() => {
      this.graph.resize(undefined, document.body.clientHeight - 60)
    }, 300), false)
  }

  _initEdge() {
    this.edge = new RuleChainEdge(this.graph)
  }
}

// 报错信息防抖
const showMsg = debounce(function() {
  Message({
    message: '并行开始节点最多只能连接6个节点',
    type: 'error'
  })
}, 300)

function MainGraph(target) {
  return new MainCanvas(target).graph
}

export default MainGraph
